//******************************************************************************
//this code is protected by the GNU affero GPLv3
//author:Sylvain BERTRAND <sylvain.bertrand AT gmail dot com>
//                        <digital.ragnarok AT gmail dot com>
//******************************************************************************
#include "globals.h"

#define LOCAL_ERR(fmt,...) \
{\
void *sysname=(void*)udev_device_get_sysname(\
registry[c->output_name].output.d);\
PERR("cfg:output:%s:layout:" fmt,sysname,##__VA_ARGS__);\
}

#define LOCAL_LOG(fmt,...) \
{\
void *sysname=(void*)udev_device_get_sysname(\
registry[c->output_name].output.d);\
LOG("cfg:output:%s:layout:" fmt,sysname,##__VA_ARGS__);\
}

#if LOG_CFG_LVL>=2
#define LOCAL_LOG_LVL2(fmt,...) LOCAL_LOG(fmt,##__VA_ARGS__);
#else
#define LOCAL_LOG_LVL2 (void)0;
#endif

void cfg_output_layout_info_defaults(struct cfg_output_layout_info *info)
{
  info->x=CFG_OUTPUT_LAYOUT_X_NOT_SET;
  info->y=CFG_OUTPUT_LAYOUT_Y_NOT_SET;
}

//errors are folded in the LAYOUT_X_NOT_SET case
static s32 x_get(struct cfg_ctx_output *c,s64 val_start,s64 line_end)
{
  LOCAL_LOG_LVL2("x key/value found\n");
  s32 r0=CFG_OUTPUT_LAYOUT_X_NOT_SET;

  s64 val_end=cfg_non_blanks_skip(&c->c,val_start,line_end);

  u32 x;
  u8 r1=dec2u32_blk(&x,c->c.m+val_start,c->c.m+val_end-1);
  if(!r1){
    LOCAL_ERR("x not a valid number\n");
    goto exit;
  }
  if(x>0x7fffffff){
    LOCAL_ERR("x(%u) above max(%u)\n",x,0x7fffffff);
    goto exit;
  }
  r0=(s32)x;
exit:
  return r0;
}

//errors are folded in the LAYOUT_Y_NOT_SET case
static s64 y_get(struct cfg_ctx_output *c,s64 val_start,s64 line_end)
{
  LOCAL_LOG_LVL2("y key/value found\n");
  s32 r0=CFG_OUTPUT_LAYOUT_Y_NOT_SET;

  s64 val_end=cfg_non_blanks_skip(&c->c,val_start,line_end);

  u32 y;
  u8 r1=dec2u32_blk(&y,c->c.m+val_start,c->c.m+val_end-1);
  if(!r1){
    LOCAL_ERR("y not a valid number\n");
    goto exit;
  }
  if(y>0x7fffffff){
    LOCAL_ERR("y(%u) above max(%u)\n",y,0x7fffffff);
    goto exit;
  }
  r0=(s32)y;
exit:
  return r0;
}

#if LOG_CFG_LVL>=2
#define LOCAL_LOG_LVL2_DUMP_LINE \
{\
u8 line_buf[129];\
memset(&line_buf[0],0,129);\
u8 sz=line_end-line_start;\
memcpy(&line_buf[0],c->c.m+line_start,sz>128?128:sz);\
LOCAL_LOG("%ld \"%s\"\n",line_start,&line_buf[0]);\
}
#else
#define LOCAL_LOG_LVL2_DUMP_LINE
#endif

#define X_KEY_STR "x"
#define Y_KEY_STR "y"

#define IS_KEY(x) (val_start-1-key_start)==cs_n(x ## _KEY_STR)\
&&!strncmp(c->c.m+key_start,x ## _KEY_STR,val_start-1-key_start)
void cfg_output_layout_info_get(struct cfg_ctx_output *c,s64 output_start,
                                            struct cfg_output_layout_info *info)
{
  s64 line_start=output_start;
  while(1){
    if((u64)line_start>=c->c.sz){
      LOCAL_LOG_LVL2("no more layout key/value:line start not in file\n");
      break;
    }

    s64 line_end=cfg_line_end_reach(&c->c,line_start);
    LOCAL_LOG_LVL2_DUMP_LINE;

    s64 key_start=cfg_blanks_skip(&c->c,line_start,line_end);

    //finished:beginning of next section reached ("[key]")
    if(*(u8*)(c->c.m+key_start)=='[') break;

    s64 val_start=cfg_key_skip_to_val(&c->c,key_start,line_end);
    if(val_start==CFG_KEY_SKIP_TO_VAL_NO_VAL){
      LOCAL_LOG_LVL2("no value\n");
    }else{
      if(IS_KEY(X)) info->x=x_get(c,val_start,line_end);
      else if(IS_KEY(Y)) info->y=y_get(c,val_start,line_end);
    }

    line_start=line_end+1;
  }
  LOCAL_LOG("x=%d y=%d\n",info->x,info->y);
}
